#include <stdio.h>
#include <stdbool.h>
#include <fcntl.h>
#include "clang-c/Index.h"
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
using namespace std;
//argv:   ./traverse ../test/adapter.cpp adapter

char* findingString = "Init";
char* nametype ="a";
int numOfArgc = 0;
const char *filename="AST.txt";

bool printKindSpelling(CXCursor cursor) {
    enum CXCursorKind curKind = clang_getCursorKind(cursor);
    const char *curkindSpelling = clang_getCString(
                                  clang_getCursorKindSpelling(curKind));
    const char *astSpelling = clang_getCString(clang_getCursorSpelling(cursor));
    CXType type=clang_getCursorType(cursor);
  //  enum CXTypeKind kind;
    printf("1.Name: %s\n", astSpelling);
       printf("2.Kind: %s , num: %d\n", curkindSpelling,curKind); 
    
    CXSourceRange range = clang_getCursorExtent(cursor);
    CXSourceLocation startLocation = clang_getRangeStart(range);
    CXSourceLocation endLocation = clang_getRangeEnd(range);
  
    CXFile file1,file2;
    unsigned int line1,line2, column1,column2, offset1,offset2;
    clang_getInstantiationLocation(startLocation, &file1, &line1, &column1, &offset1);
    printf("3.Start: Line: %u Column: %u Offset: %u\n", line1, column1, offset1);
    clang_getInstantiationLocation(endLocation, &file2, &line2, &column2, &offset2);
    printf("4.End: Line: %u Column: %u Offset: %u\n", line2, column2, offset2);
     
       if(curKind==21)
       {
      printf("isStatic: %d\n",clang_CXXMethod_isStatic(cursor)); 
         printf("#####type: %s\n",clang_getTypeSpelling(type));
          printf("kind: %d\n",type.kind);
       }
       if(curKind==6||curKind==10||curKind==21||curKind==24)
       {
     printf("######type: %s\n",type); 
      printf("#####type: %s\n",clang_getTypeSpelling(type));
    //  printf("name: %s\n",clang_getTypedefName(type));
     printf("kind: %d\n",type.kind);
     }        
                         //curkind=43,constructExpr.
       char* ast=new char[50];
      strcpy(ast,"AST/");
      strcat(ast,filename); //新文件会建在pre的AST文件夹下，而不是traverse的文件夹下
       strcat(ast,".txt"); 
     FILE *fp = fopen(ast,"a+");
    if(NULL == fp)
    {
        printf("open failed");
        return -1;
    }
fprintf(fp,"%d,%s,%d,%d,%d,%d,",curKind,astSpelling,line1,column1,line2,column2); 
       if(curKind==6||curKind==10||curKind==21||curKind==24||curKind==101||curKind==103||curKind==9||curKind==102||curKind==100)
   {
    fprintf(fp,"%s,",clang_getTypeSpelling(type));
    }
    fprintf(fp,"\n");
    fclose(fp);
     
    /*
   ofstream outFile;
  if (!outFile)
  {
     cout<<"no file"<<endl; 
  }
  else{
      char* ast=new char[50];
      strcpy(ast,"AST/");
      strcat(ast,filename); //新文件会建在pre的AST文件夹下，而不是traverse的文件夹下
      outFile.open(ast,ios::app); // 打开模式可省略  
  } 

   
  // outFile<<curKind<","<<curkindSpelling<<","<<endl;
          outFile<<curKind<<","<<astSpelling<<","<<line1<<","<<column1<<","<<line2<<","<<column2;
//   outFile<<"1.Name: "<<astSpelling;
//   outFile<<"4.Start Line: "<<line1<<", Start Column: "<<column1;
//   outFile<<", 5.End Line: "<<line2<<", End Column: "<<column2<<endl;
     if(curKind==6||curKind==10)
   {
     //outFile<<","<<(clang_getTypeSpelling(type));
   }     
    outFile<<endl;
   outFile.close();
    */
    return true;
}


enum CXChildVisitResult printVisitor(CXCursor cursor, CXCursor parent,
                                     CXClientData client_data) {
    const char *astSpelling = clang_getCString(clang_getCursorSpelling(cursor));
    if (numOfArgc == 4) {
        if (strcmp(astSpelling, findingString) == 0) {
            printKindSpelling(cursor);
        }
    } else {
        printKindSpelling(cursor);


    }
    return CXChildVisit_Recurse;
}

int main(int argc, char *argv[]) {
    if ((argc > 3) || (argc < 2)) {
        printf("You input wrong number arguments!\n");
        return -1;
    }

    if ((strcmp(argv[1],"-v")) == 0) {   //一个参数，提示信息
        printf("scread   version:0.1\n");
        printf("Author   shining\n");
        printf("Mail:shiningning1984@gmail.com\n");
        return 0;
    }else if ((strcmp(argv[1],"-help")) == 0) {
        printf("scread <filename>              The scread will output all the AST nodes' information\n");
        printf("scread <filename> <keyword>    The scread will output the AST nodes' matched the keyword.\n");
        printf("scread -v                      The scread will output the version information.\n");
        printf("scread -help                   The scread will output the help information.\n");
        return 0;
    }else {
        int result = open(argv[1], O_RDONLY);
        if (result == -1) {
            printf("Can't open the file: %s.\n", argv[1]);
            return -1;
        }
    }

    numOfArgc = argc;  
    if (numOfArgc == 3) {  //两个参数，带解析文件路径
   //    findingString = argv[2];
    filename=argv[2];
    }
    
    if (numOfArgc == 4) { //三个参数，要检查的字段
        findingString = argv[3];
   
    }

    CXIndex Index = clang_createIndex(0,0);
    CXTranslationUnit TU = clang_parseTranslationUnit(Index, 0, argv, argc,
                                                      0, 0,
                                                      CXTranslationUnit_None);
    CXCursor C = clang_getTranslationUnitCursor(TU);

    printKindSpelling(C);

 
    clang_visitChildren(C, printVisitor, NULL);

    clang_disposeTranslationUnit(TU);
    clang_disposeIndex(Index); 
        printf("### %s\n",filename);
    return 0;
}